package src.E_Thread;

import java.util.ArrayList;
import java.util.List;

/*
ArrayLIst，HashSet，HashMap 等都是不安全的

ArrayList
    产生原因：普通的 ArrayList 集合里面没有任何特殊处理，在多线程情况下，他们可以共同进行访问。
        1、值覆盖问题，因为 ArrayList 的底层数组，写入值的时候要先计算到一个下标位置，然后给对应的位置去赋值，多线程就会出现值覆盖的问题
        2、空指针异常，因为 ArrayList 的底层数组，写入值在数组满的时候需要扩容，在扩容还没完成的时候，新的下标却已经计算出来并且要去插入，那么就会出现空指针异常
        3、并发修改异常，普通读写不一致问题，在遍历list的时候有可能还有线程在对list进行修改操作，导致抛出异常
    解决方法：用其他代替类
        1、使用Vector，它是线程安全的集合
        2、数据量小的时候，使用 Collections.synchronizedList(new ArrayList())这种方式，来包裹这个集合
        3、直接使用 juc 包里面的，CopyOnWriteArrayList() 类，这个类就是并发包给我们提供的线程安全的列表类，读写分离

HashSet（hashset底层是hashmap实现的）
    产生原因：并发修改异常，同上3
    解决方法：用其他代替类
        1、数据量小的时候，使用 Collections.synchronizedSet(new HashSet<>()) 这种方式，来包裹这个集合
        2、直接使用 juc 包里面的，CopyOnWriteArraySet() 类，读写分离（注意：该类的底层并不是hashmap对应的安全类实现的，而是CopyOnWriteArrayList()类！）

HashMap
    产生原因：
        1、普通读写不一致问题，同上3
        2、死循环问题
    解决方法：用其他代替类
        1、数据量小的时候，使用 Collections.synchronizedMap(new HashMap())这种方式，来包裹这个集合
        2、直接使用 juc 包里面的，ConcurrentHashMap() 类，读写分离
*/

// 不安全线程，示例三（线程不安全的集合）
public class E15_UnsafeThread03 {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> { // 同一时间可能会有两个或多个线程添加到同一个位置，导致不安全
                synchronized (list){ // 现在安全了
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        // 这里如果把延迟去掉就算加了锁也不能保证下面每次都输出1w，因为当main线程比子线程跑的快时，下面就打印了，实际打印的时候子线程还没跑完，但是安全的
        Thread.sleep(1000); // 模拟延迟，
        System.out.println(list.size()); // 大小并不是每次都是1w，不安全；加了锁和延时后现在每次打印都是1w了
    }
}
